package GeneralObjects;

import java.io.IOException;

import ArithmeticObjects.Element;
import ArithmeticObjects.Group;
import ArithmeticObjects.ModularGroupElement;
import ArithmeticObjects.ProductGroupElement;
import utils.ByteTree;

/**
 * Representing a CipherText
 * @author Idan
 */
public class CipherText {
	private ProductGroupElement e; 
	
	/**
	 * creates a CipherText from a ProductGroupElement representing it
	 * @param e ProductGroupElement representing the CipherText
	 */
	public CipherText(ProductGroupElement e)
	{
		this.e = e;
	}
	
	/**
	 * creates a CipherText from a ByteTree representing it as a ProductGroupElement and a Group indicating its order
	 * @param bt the ByteTree representing the CipherText as a ProductGroupElement
	 * @param Gq the Group indicating its order
	 * @throws Exception in case the ProductGroupElement representing the CipherText could not be constructed
	 */
	public CipherText(ByteTree bt, Group Gq) throws Exception
	{
		e = new ProductGroupElement(bt, Gq);
	}
	
	/**
	 * creates a CipherText from two ByteTree nodes representing the CipherText as left and right
	 * sub trees and a Group indicating its order
	 * @param left left ByteTree node representing the left node of a ProductGroupElement
	 * @param right right ByteTree node representing the left node of a ProductGroupElement
	 * @param Gq a Group indicating its order
	 * @throws Exception in case the ProductGroupElement representing the CipherText could not be constructed
	 */
	public CipherText(ByteTree left, ByteTree right, Group Gq) throws Exception
	{
		ByteTree bt = ByteTree.CreateNode();
		bt = bt.AddMultiChildsToNode(left,right);
		e = new ProductGroupElement(bt, Gq);
	}
	
	/**
	 * compares the current CipherText to another 
	 * @param elementA a CipherText to compare to
	 * @return 0 if the CipherTexts are equal and 1 otherwise
	 * @throws Exception in case the ProductGroupElements are not of the same structure
	 */
	public int compareTo(CipherText elementA) throws Exception
	{
		return e.compareTo(elementA.getElement());
	}
	
	/**
	 * raise all elements in the ProductGroupElement by the power of exponent
	 * @param exponent the exponent to raise by
	 * @return a CipherText where all elements are raised by the power of exponent
	 * @throws Exception if the power operation failed
	 */
	public CipherText power(Element exponent) throws Exception
	{
		return new CipherText((ProductGroupElement)e.power(exponent));
	}
	
	/**
	 * adds the current CipherText to another coordinate wise 
	 * @param c the CipherText added to the current one
	 * @return the current CipherText after the addition operation was complete
	 * @throws Exception if the addition operation failed
	 */
	public CipherText add(CipherText c) throws Exception
	{
		return new CipherText((ProductGroupElement)e.add(c.getElement()));
	}
	
	/**
	 * subtracts the current CipherText from another coordinate wise 
	 * @param c the CipherText subtracted from the current one
	 * @return the current CipherText after the subtraction operation was complete
	 * @throws Exception if the subtraction operation failed
	 */
	public CipherText subtract(CipherText c) throws Exception
	{
		return new CipherText((ProductGroupElement)e.subtract(c.getElement()));
	}
	
	/**
	 * multiplies the current CipherText by another coordinate wise 
	 * @param c the CipherText multiplied by the current one
	 * @return the current CipherText after the multiplication operation was complete
	 * @throws Exception if the multiplication operation failed
	 */
	public CipherText multiply(CipherText c) throws Exception
	{
		return new CipherText((ProductGroupElement)e.multiply(c.getElement()));
	}
	
	/**
	 * divides the current CipherText by another coordinate wise 
	 * @param c the CipherText divided by the current one
	 * @return the current CipherText after the division operation was complete
	 * @throws Exception if the division operation failed
	 */
	public CipherText divide(CipherText c) throws Exception
	{
		return new CipherText((ProductGroupElement)e.divide(c.getElement()));
	}
	
	/**
	 * @return the left node of the CipherText represented as a ProductGroupElement
	 * @throws Exception in case the ProductGroupElement construction failed
	 */
	public Element getLeftChild() throws Exception {
		return new ProductGroupElement(e.getByteTree().getChild(0),e.getGroup());
	}
	/**
	 * @return the right node of the CipherText represented as a ProductGroupElement
	 * @throws Exception in case the ProductGroupElement construction failed
	 */	
	public Element getRightChild() throws Exception {
		return new ProductGroupElement(e.getByteTree().getChild(1),e.getGroup());
	}
	
	/**
	 * @return the left node of the CipherText represented as a ModularGroupElement
	 * @throws Exception in case the ModularGroupElement construction failed
	 */
	public Element getLeftElement() throws Exception {
		return new ModularGroupElement(e.getByteTree().getChild(0),e.getGroup());
	}
	/**
	 * @return the right node of the CipherText represented as a ModularGroupElement
	 * @throws Exception in case the ModularGroupElement construction failed
	 */	
	public Element getRightElement() throws Exception {
		return new ModularGroupElement(e.getByteTree().getChild(1),e.getGroup());
	}	
	
	/**
	 * @return the ProductGroupElement representing the CipherText
	 */
	public Element getElement()
	{
		return e;
	}

	public ByteTree getByteTree() throws IOException {
		return e.getByteTree();
	}
}
